using System;
using System.Collections.Generic;
using System.Drawing;

using OpenTK;

namespace ColladaDotNet.SimpleMesh
{
	public class Vertex : IEquatable<Vertex>
	{
		public Vector3d Position;

		public Vector3d Normal;

		public Vector4d Color;

		public Mapping TexCoord0;

		public Mapping TexCoord1;

		public Mapping TexCoord2;

		public VertexBone[] Bones;

		public Color ColorValue
		{
			get
			{
				return System.Drawing.Color.FromArgb((byte)(Color.X * 255.0), (byte)(Color.Y * 255.0), (byte)(Color.Z * 255.0), (byte)(Color.W * 255.0));
			}
			set
			{
				Color = new Vector4d(value.R / 255.0, value.G / 255.0, value.B / 255.0, value.A / 255.0);
			}
		}

		/// <summary>
		/// Indicates whether the current object is equal to another object of the same type.
		/// </summary>
		/// <returns>
		/// true if the current object is equal to the other parameter; otherwise, false.
		/// </returns>
		/// <param name="obj">An object to compare with this object.</param>
		public bool Equals(Vertex obj)
		{
			return obj.Position.Equals(Position) && obj.Normal.Equals(Normal) && obj.Color.Equals(Color) && obj.TexCoord0.Equals(TexCoord0) && obj.TexCoord1.Equals(TexCoord1) && obj.TexCoord2.Equals(TexCoord2) && IsBoneEquals(obj.Bones, Bones);
		}

		private static bool IsBoneEquals(VertexBone[] bones, VertexBone[] vertexBones)
		{
			if ((bones == null || bones.Length == 0) && (vertexBones == null || vertexBones.Length == 0))
				return true;
			if ((bones == null || bones.Length == 0) || (vertexBones == null || vertexBones.Length == 0))
				return false;
			if (bones.Length != vertexBones.Length)
				return false;
			for (int i = 0; i < bones.Length; ++i)
			{
				for (int j=0; j<vertexBones.Length;++j)
					if (bones[i].Index == vertexBones[j].Index)
					{
						if (bones[i].Weight != vertexBones[i].Weight)
							return false;
						goto nextBone;
					}
				if (bones[i].Weight != 0)
					return false;
			nextBone:
				;
			}
			return true;
		}

		/// <summary>
		/// Indicates whether this instance and a specified object are equal.
		/// </summary>
		/// <returns>
		/// true if obj and this instance are the same type and represent the same value; otherwise, false.
		/// </returns>
		/// <param name="obj">Another object to compare to. </param><filterpriority>2</filterpriority>
		public override bool Equals(object obj)
		{
			if (obj.GetType() != typeof(Vertex))
			{
				return false;
			}
			return Equals((Vertex)obj);
		}

		/// <summary>
		/// Returns the hash code for this instance.
		/// </summary>
		/// <returns>
		/// A 32-bit signed integer that is the hash code for this instance.
		/// </returns>
		/// <filterpriority>2</filterpriority>
		public override int GetHashCode()
		{
			unchecked
			{
				int result = Position.GetHashCode();
				result = (result * 397) ^ Normal.GetHashCode();
				result = (result * 397) ^ Color.GetHashCode();
				result = (result * 397) ^ TexCoord0.GetHashCode();
				result = (result * 397) ^ TexCoord1.GetHashCode();
				result = (result * 397) ^ TexCoord2.GetHashCode();
				if (Bones != null)
					foreach (var bone in Bones)
					{
						result = (result * 397) ^ (bone.GetHashCode());
					}
				return result;
			}
		}

		public static bool operator ==(Vertex left, Vertex right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(Vertex left, Vertex right)
		{
			return !left.Equals(right);
		}

		public VertexBone[] GetMostImportantBones(int num)
		{
			if (Bones == null)
				return new VertexBone[]{};
			if (Bones.Length == 1)
				return Bones;
			if (num >= Bones.Length)
				num = Bones.Length;// return Bones;
			var buf = new VertexBone[Bones.Length];
			Array.Copy(Bones,buf,buf.Length);
			Array.Sort(buf, new VertexBoneComparer());
			var res = new VertexBone[num];
			Array.Copy(buf,res,num);
			double sum = 0;
			foreach (var vertexBone in res)
			{
				sum += vertexBone.Weight;
			}
			sum = 1.0 / sum;
			for (int i = 0; i < res.Length; i++)
			{
				res[i].Weight *= sum;
			}
			return res;
		}

		public void Scale(double factor)
		{
			Position = Position * factor;
		}
	}
}